package com.youdoneed.application;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.youdoneed.common.JWTUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.regex.Pattern;

@Component
public class AccessFilter extends ZuulFilter {
    private static Logger log = LoggerFactory.getLogger(AccessFilter.class);

    // 公开的请求地址不做拦截
    @Value("${accessFilter.publicUris}")
    private String[] publicUris;

    // Pattern是线程安全的，只编译一次以提高性能
    private Pattern[] publicPatterns;

    @PostConstruct
    private void initPatterns() {
        publicPatterns = new Pattern[publicUris.length];
        for (int i = 0; i < publicUris.length; i++) {
            publicPatterns[i] = Pattern.compile(publicUris[i]);
        }
    }

    /**
     * pre：这种过滤器在请求被路由之前调用。
     * routing：这种过滤器将请求路由到微服务。
     * post：这种过滤器在路由到微服务以后执行。
     * error：在其他阶段发生错误时执行该过滤器。
     */
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String path = ctx.getRequest().getRequestURI();
        for (Pattern publicPattern : publicPatterns) {
            if (publicPattern.matcher(path).matches()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public Object run() {
        // RequestContext是线程共享的
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        // 验证并解析JWT数据
        String token = request.getHeader("Authorization");
        if (StringUtils.hasText(token)) {
            JWTUtils.getClaimsValidate(token);
        } else {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.getResponse().setContentType("text/plain;charset=utf-8");
            ctx.setResponseBody("该请求需要有效的令牌。\nRequest requires a valid token.");
        }
        return null;
    }

}